package com.zhangmeng.tools.controller;

import cn.hutool.core.io.BufferUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.ssh.ChannelType;
import cn.hutool.extra.ssh.JschRuntimeException;
import cn.hutool.extra.ssh.JschUtil;
import cn.hutool.extra.template.Template;
import cn.hutool.extra.template.TemplateConfig;
import cn.hutool.extra.template.TemplateEngine;
import cn.hutool.extra.template.TemplateUtil;
import cn.hutool.socket.aio.AioSession;
import cn.hutool.socket.aio.SimpleIoAction;
import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.jcraft.jsch.*;
import com.zhangmeng.tools.ssh.*;
import com.zhangmeng.tools.utils.AlertUtils;
import javafx.application.Platform;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.concurrent.Worker;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import lombok.extern.slf4j.Slf4j;
import netscape.javascript.JSObject;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.java_websocket.WebSocket;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.drafts.Draft_6455;
import org.java_websocket.handshake.ClientHandshake;
import org.java_websocket.handshake.ServerHandshake;
import org.java_websocket.server.WebSocketServer;

import java.io.*;
import java.net.InetSocketAddress;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Properties;

import static cn.hutool.extra.ssh.JschUtil.*;

/**
 * @author : 芊芊墨客
 * @version : 1.0
 * @date : 2023-03-11 17:10
 */
@Slf4j
public class SSHConnectionController {

    @FXML
    public Button connection;

//    @FXML
//    public TextArea show_result;
//
//    @FXML
//    public TextField command;

    @FXML
    public WebView webView;

    @FXML
    private TextField username;

    @FXML
    private TextField password;

    @FXML
    private TextField host;

    @FXML
    private TextField port;

    private SimpleObjectProperty<String> uuid = new SimpleObjectProperty<>("202331112221255544555");
    private SimpleObjectProperty<Integer> status = new SimpleObjectProperty<>(0);
    public static ObservableList<String> message_list = FXCollections.observableArrayList();

    private WebSocketServer webSocketServer;
    private WebSocketClient webSocketClient;
    private SSHService sshService;

    private boolean isConnection = false;

    @FXML
    public void initialize() {

        username.setText("root");
        password.setText("root");
        host.setText("192.168.52.165");
        port.setText("22");

        message_list.addListener((ListChangeListener<String>) c -> {
            while (c.next()) {
                if (c.wasAdded()) {
                    StringBuilder stringBuilder = new StringBuilder();
                    for (String s : message_list) {
                        stringBuilder.append(s);
                    }
                    receive(stringBuilder.toString());
                }
            }
        });
        sshService = new SSHServiceImpl();
        //初始化
        sshServer_init();
        connection.setOnAction(event -> {
            if (username.getText().length() == 0) {
                AlertUtils.alert_warning("用户名不能为空!");
                return;
            }

            if (password.getText().length() == 0) {
                AlertUtils.alert_warning("密码不能为空!");
                return;
            }

            if (host.getText().length() == 0) {
                AlertUtils.alert_warning("服务地址不能为空!");
                return;
            }

            if (port.getText().length() == 0) {
                AlertUtils.alert_warning("服务端口不能为空!");
                return;
            }

            if (isConnection) {
                try {
                    webSocketServer.stop();
                    Thread.sleep(100);
                    isConnection = false;
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            sshServer_init();
            webSocketServer.start();
//            getConnection();
//            try {
//                Thread.sleep(1000);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//            发送连接信息
//            SSHData ssh_data = create_ssh_data(command.getText(), SSHData.Type.connect);
//            webSocketClient.send(toString(ssh_data));

            isConnection = true;
            //加载页面客户端
            load_page_client();
            status.set(1);
        });
//        command.textProperty().addListener((observable, oldValue, newValue) -> {
//            if (newValue != null){
//                char[] chars = newValue.toCharArray();
//                char num = 0;
//                for (int i = 0; i < chars.length; i++) {
//                    if (i == chars.length -1 ){
//                        num = chars[i];
//                    }
//                }
//                SSHData ssh_data = create_ssh_data(String.valueOf(num), SSHData.Type.command);
//                webSocketClient.send(toString(ssh_data));
//            }
//
//        });
//        command.setOnAction(event -> {
//            SSHData ssh_data = create_ssh_data("\r", SSHData.Type.command);
//            webSocketClient.send(toString(ssh_data));
//            command.setText(null);
//        });
    }

    public void sshServer_init(){
        //启动socket server
        webSocketServer = new WebSocketServer(new InetSocketAddress(8888)) {

            @Override
            public void onOpen(WebSocket webSocket, ClientHandshake clientHandshake) {
                sshService.initConnection(webSocket, uuid.getValue());
            }

            @Override
            public void onClose(WebSocket webSocket, int i, String s, boolean b) {
                add_msg("WebSocketServer:onClose--------------------------------------------");
                sshService.close(webSocket, uuid.getValue());
            }

            @Override
            public void onMessage(WebSocket webSocket, String s) {
                sshService.recvHandle(s, webSocket, uuid.getValue());
            }

            @Override
            public void onError(WebSocket webSocket, Exception e) {
                add_msg("WebSocketServer:onError--------------------------------------------");
            }

            @Override
            public void onStart() {
                add_msg("WebSocketServer:onStart--------------------------------------------");
            }
        };
    }

    public void load_page_client() {
        WebEngine webEngine = webView.getEngine();
        TemplateEngine engine = TemplateUtil.createEngine(new TemplateConfig("templates", TemplateConfig.ResourceMode.CLASSPATH));
        Template template = engine.getTemplate("index.ftl");

        Dict dict = Dict.create();
        dict.set("username", username.getText());
        dict.set("password", password.getText());
        dict.set("host", host.getText());
        dict.set("port", port.getText());

        String result = template.render(dict);

        URI url = null;
        try {
            url = this.getClass().getClassLoader().getResource("templates/ssh.html").toURI();
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }
        FileUtil.writeBytes(result.getBytes(StandardCharsets.UTF_8), url.getPath());
        webEngine.load(url.toASCIIString());
    }

    private String toString(SSHData sshData) {
        return JSON.toJSONString(sshData);
    }

    public SSHData create_ssh_data(String command, SSHData.Type type) {
        SSHData sshData = new SSHData();
        sshData.setUsername(username.getText());
        sshData.setPassword(password.getText());
        sshData.setHost(host.getText());
        sshData.setPort(Integer.parseInt(port.getText()));
        sshData.setOperate(type);
        sshData.setCommand(command);
        return sshData;
    }

    private void getConnection() {
        if (webSocketClient == null) {
            webSocketClient("localhost", 8888);
        }
    }

    public void webSocketClient(String socket_address, int socket_port) {
        try {
            webSocketClient = new WebSocketClient(new URI("ws://" + socket_address + ":" + socket_port), new Draft_6455()) {
                //连接服务端时触发
                @Override
                public void onOpen(ServerHandshake handshakedata) {
                    add_msg("websocket客户端和服务器连接成功!");
                }

                //收到服务端消息时触发
                @Override
                public void onMessage(String message) {
                        add_msg(message);
                }

                //和服务端断开连接时触发
                @Override
                public void onClose(int code, String reason, boolean remote) {
                    add_msg("websocket客户端退出连接");
                }

                //连接异常时触发
                @Override
                public void onError(Exception ex) {
                    add_msg("websocket客户端和服务器连接发生错误={" + ex.getMessage() + "}");
                }
            };
            webSocketClient.connect();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void add_msg(String msg) {
        message_list.add(msg);
        message_list.add(System.lineSeparator());
    }

    public void receive(String msg) {
        Platform.runLater(() -> {
           // this.show_result.setText(msg);
        });
    }

}
